package com.lin.fengxiu.logic;

import com.lin.fengxiu.bo.SkuOrderBO;
import com.lin.fengxiu.core.enumeration.CouponType;
import com.lin.fengxiu.core.money.HalfEvenRound;
import com.lin.fengxiu.core.money.IMoneyDiscount;
import com.lin.fengxiu.exception.http.ForbiddenException;
import com.lin.fengxiu.exception.http.ParameterException;
import com.lin.fengxiu.model.Category;
import com.lin.fengxiu.model.Coupon;
import com.lin.fengxiu.util.CommonUtil;
import com.sun.org.apache.bcel.internal.generic.BREAKPOINT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName CouponChecker
 * @Description TODO 优惠券检测
 * @Author wushaopei
 * @Date 2021/4/3 12:21
 * @Version 1.0
 */
public class CouponChecker {

    private Coupon coupon;
//    private UserCoupon userCoupon;
    private IMoneyDiscount iMoneyDiscount;

    public CouponChecker(Coupon coupon, IMoneyDiscount iMoneyDiscount){
        this.coupon = coupon;
//        this.userCoupon = userCoupon;
        this.iMoneyDiscount = iMoneyDiscount;
    }

    /**
     * @Description TODO 优惠券基础检测 —— 优惠券是否过期
     */
    public void isOk(){
        // 根据coupon的startTime、endTime来判断是否过期
        Date now = new Date();
        Boolean isInTimeLine = CommonUtil.isInTimeLine(now,this.coupon.getStartTime(),this.coupon.getEndTime());
        if(!isInTimeLine){
            throw new ForbiddenException(40007);
        }
    }

    /**
     * @Description TODO 优惠券真正的成交价格 —— 复查成交价，因为前端传过来的OrderDTO的是不可信的
     * @param orderFinalTotalPrice 前端传过来的支付价格
     * @param serverTotalPrice  后台计算的支付价
     */
    public void finalTotalPriceIsOk(BigDecimal orderFinalTotalPrice,
                                    BigDecimal serverTotalPrice){
        BigDecimal serverFinalTotalPrice;

        // 判断当前的优惠券类型
        switch (CouponType.toType(this.coupon.getType())){
            // 满减券
            case FULL_MINUS:
            // 无门槛
            case NO_THRESHOLD_MINUS:
                // 获取后台满减后支付总额
                serverFinalTotalPrice = serverTotalPrice.subtract(this.coupon.getMinus());
                // 无门槛券需要校验是否为负值，即10元减30元为-20元这种情况，这是不能发生的
                if(serverFinalTotalPrice.compareTo(new BigDecimal("0")) <= 0){
                    throw new ForbiddenException(50008);
                }
                break;
            // 满减折扣券
            case FULL_OFF:
                serverFinalTotalPrice = this.iMoneyDiscount.discount(serverTotalPrice,this.coupon.getRate());
                break;
            default:
                throw new ParameterException(40009);
        }
        // 校验前后端支付总额
        int compare = serverFinalTotalPrice.compareTo(orderFinalTotalPrice);
        if(compare != 0){
            throw new ForbiddenException(50008);
        }
    }

    /**
     * @Description TODO 核对当前的优惠券是否能够使用，影响优惠券是否可以使用的因素有：满减金额、品类等
     * @param skuOrderBOList 业务模型
     * @param serverTotalPrice 后端订单总价格
     */
    public void canBeUsed(List<SkuOrderBO> skuOrderBOList, BigDecimal serverTotalPrice){
        BigDecimal orderCategoryPrice;

        // 如果是全场券，则订单分类总额等于后台计算的总额
        if(this.coupon.getWholeStore()){
            orderCategoryPrice = serverTotalPrice;
        }
        else{
            // 获取订单分类id
            List<Long> cidList = this.coupon.getCategoryList()
                    .stream()
                    .map(Category::getId)
                    .collect(Collectors.toList());
            // 获取订单折扣金额
            orderCategoryPrice = this.getSumByCategoryList(skuOrderBOList,cidList);
        }
        // 比较优惠券折扣后金额与前端传的金额
        // 不是所有的优惠券都需要进行分类的
    }

    /**
     * @Description TODO 根据优惠券类型进行分类计算后的金额和原始金额的校验，
     * @param orderCategoryPrice
     */
    private void couponCanBeUsed(BigDecimal orderCategoryPrice){
        switch (CouponType.toType(this.coupon.getType())){
            case FULL_OFF:
            case FULL_MINUS:
                // fullMoney 是优惠券使用门槛的价格，如果当前分类总额小于门槛价格，则不能使用优惠券
                int compare = this.coupon.getFullMoney().compareTo(orderCategoryPrice);
                if(compare > 0){
                    throw new ParameterException(40008);
                }
                break;
            case NO_THRESHOLD_MINUS:
                break;
            default:
                throw new ParameterException(40008);
        }
    }

    /**
     * @Description TODO 计算多个sku的总价
     * @param skuOrderBOList
     * @param cidList
     * @return
     */
    private BigDecimal getSumByCategoryList(List<SkuOrderBO> skuOrderBOList, List<Long> cidList){
        BigDecimal sum = cidList.stream()
                .map(cid -> this.getSumByCategory(skuOrderBOList,cid))
                .reduce(BigDecimal::add)
                .orElse(new BigDecimal("0"));
        return sum;
    }

    /**
     * @Description TODO 计算单个sku的总价
     * @param skuOrderBOList 订单的skuList
     * @param cid 所属分类id
     * @return
     */
    private BigDecimal getSumByCategory(List<SkuOrderBO> skuOrderBOList, Long cid){
        BigDecimal sum = skuOrderBOList.stream()
                .filter(sku-> sku.getCategoryId().equals(cid))  // 过滤符合cid 的sku
                .map(bo->bo.getTotalPrice())                    // 获取符合当前sku数量的总金额
                .reduce(BigDecimal::add)                        // 使用reduce对 .map（）的结果进行累加
                .orElse(new BigDecimal("0"));
        return sum;
    }

}
